# 初级神经网络demo，用于解决异或（XOR）问题的二分类任务
import numpy as np  # 仅用于生成数据，核心逻辑不依赖库

# 注意：实际应用中应避免重复造轮子，此处仅为教学目的
# -----------------------------------------------------
# 生成异或(XOR)数据集
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])

# 参数初始化（手动实现）
input_size = 2
hidden_size = 2
output_size = 1
learning_rate = 0.1
epochs = 10000


# 权重初始化（不使用第三方库的随机数生成）
def manual_init(rows, cols):
    return [[(hash(f"{i},{j}") % 1000) / 1000 - 0.5 for j in range(cols)] for i in range(rows)]


# 初始化权重和偏置
W1 = manual_init(input_size, hidden_size)  # 输入层到隐藏层
b1 = [0.0 for _ in range(hidden_size)]
W2 = manual_init(hidden_size, output_size)  # 隐藏层到输出层
b2 = [0.0]


# 激活函数（Sigmoid）
def sigmoid(x):
    return 1 / (1 + pow(2.718281828459045, -x))  # 用幂运算替代math.exp


# 前向传播
def forward(x):
    # 输入层 -> 隐藏层
    h_input = [sum(x_i * W1[i][j] for i, x_i in enumerate(x)) + b1[j] for j in range(hidden_size)]
    h_output = [sigmoid(v) for v in h_input]

    # 隐藏层 -> 输出层
    o_input = sum(h * W2[j][0] for j, h in enumerate(h_output)) + b2[0]
    o_output = sigmoid(o_input)
    return h_output, o_output


# 训练过程
for epoch in range(epochs):
    total_loss = 0
    for x, target in zip(X, y):
        # 前向传播
        h_out, o_out = forward(x)

        # 计算损失（均方误差）
        loss = 0.5 * (target[0] - o_out) ** 2
        total_loss += loss

        # 反向传播（手动计算梯度）
        # 输出层梯度
        d_loss = (o_out - target[0]) * o_out * (1 - o_out)

        # 隐藏层梯度
        d_hidden = [h_out[j] * (1 - h_out[j]) * W2[j][0] * d_loss for j in range(hidden_size)]

        # 更新权重
        # 更新W2和b2
        for j in range(hidden_size):
            W2[j][0] -= learning_rate * d_loss * h_out[j]
        b2[0] -= learning_rate * d_loss

        # 更新W1和b1
        for i in range(input_size):
            for j in range(hidden_size):
                W1[i][j] -= learning_rate * d_hidden[j] * x[i]
        for j in range(hidden_size):
            b1[j] -= learning_rate * d_hidden[j]

    # 每2000次输出损失
    if epoch % 2000 == 0:
        print(f"Epoch {epoch}, Loss: {total_loss / 4}")

# 测试预测
print("\nFinal Predictions:")
for x in X:
    _, pred = forward(x)
    print(f"{x} -> {pred:.4f} (expected {y[np.where((X == x).all(axis=1))[0][0]][0]})")